<?
/*namespace PHPLego;*/

abstract class lego_abstract{
    static protected $runned_legos = array();
    static protected $all_legos = array();
	private $name;
	private $default_action = "index";
    private $lego_runner;
    private $output_handler;
    private $current_action;
	protected $output = "";
	protected $dir;
    static public $sitemap;
    static public $get;
    
    static public function staticConsturct(){
    	if(class_exists("SiteMap"))
        	self::$sitemap = new SiteMap();
        self::$get = new QueryString($_GET);
    }
    
    
	public function __construct($name = false){
		self::$all_legos[] = $this;
        $this->lego_runner = lego_abstract::current();
        self::$runned_legos[] = $this;
		if(!$name) $name = get_class($this);
		$this->name = $name;
		$this->dir = $this->getDir();
		$this->init();
	}
	
	public function init(){}
	
	public function getVersion(){return 0;}
	
    public function getSitemap(){
        return self::$sitemap;
    }

    public function setDefaultAction($default_action){
        $this->default_action = $default_action;
    }
	public function getDefaultAction(){
		return $this->default_action;
	}
    
    function getActions(){
        $methods = get_class_methods(get_class($this));
        $ret = array();
        foreach($methods as $one)
            if(strpos($one, "action_") === 0 && strpos($one, "action_submit") !== 0)
                $ret[] = substr($one, strlen("action_"));
        return $ret;
    }
    
	public function run(){
        $this->beforeRun();
        Output::assign("lego", $this);
		$act = $this->getAction();
		$method_name = "action_$act";
		if(!method_exists($this, $method_name)) $method_name = "action_default";
		if(method_exists($this, $method_name)){
			try{	
                $this->current_action = $act;                                    
				$this->output = call_user_func_array(array($this, $method_name), $this->getActionParams());
				//$this->output = $this->{$method_name}();
			}
			catch(Exception $e){
				if(preg_match("/Table .*? doesn't exist/i", $e->getMessage())){
					$this->install();
                }
                throw $e;
			}
		}
		else
			$this->output = $this->_404("wrong action ($method_name) [class=". get_class($this)."]");
        Output::assign("lego", $this->runner());
        $this->afterRun();
	}
	
	public function getAction(){
		$act = $this->_get($this->name, $this->default_action);
        if(!is_array($act)) return $act;
        if(isset($act["act"])) return $act["act"];
        return $this->default_action;
	}
    
    private function beforeRun(){
        /*if(self::isLegoRunned($this->getName()))
            throw new Exception("Лего с именем '{$this->getName()}' запущено дважды");*/
    }
    
    private function afterRun(){
        array_pop(self::$runned_legos);
        if($this->_get("ajax") == $this->getName()){
        	echo $this->output;
        	die;
		}
    }
    
    static public function isLegoRunned($name){
        foreach(self::$runned_legos as $lego)
            if($lego->getName() == $name) return true;
        return false;
    }
    
    static public function getAllNames(){
    	$ret = array();
    	foreach(self::$all_legos as $lego){
    		$ret[] = $lego->getName();
		}
		return array_unique($ret);
	}
	
	public function _404($text){
		return($text);
	}
    
    public function _goto($url){
    	$ajax_element = $this->_get("ajax");
    	if($ajax_element){
    		$info = parse_url($url);
    		$get = array();
    		if(!empty($info['query'])) parse_str($info['query'], $get);
    		$info['query'] = http_build_query(array_merge($get, array(Ajax::key() => $ajax_element)));
    		$url = (isset($info['scheme']) ? $info['scheme']."://" : "")
    			.(isset($info['host']) ? $info['host'] : "")
    			.(isset($info['path']) ? $info['path'] : "")
    			.(isset($info['query']) ? "?".$info['query'] : "");
		}
        header("Location: ".$url);
        exit;
    }
    
    public function _gotoAct($action){
    	$this->_goto($this->actUri($action)->url());
	}
	
	public function getName(){
		return $this->name;
	}
	
	public function getOutput(){
		if(is_callable($this->output_handler))
			return call_user_func($this->output_handler, $this->output, $this);
		return $this->output;
	}
	
	public function setOutputHandler($func){
		$this->output_handler = $func;
	}
	
	public function actUri($action){
        $params = func_get_args();
        array_unshift($params, $this->getName());
        return call_user_func_array(
            array($this->uri(), "set"),
            $params
        );
	}
	
	public function uri(){
		return new UriConstructor();
	}
	
	public function getLegoParams($lego_name = false){
		if(!$lego_name) $lego_name = $this->getName();
		return $this->_get($lego_name, array());
	}
	
	public function getLegoParam($param_name, $lego_name = false){
		$lego_params = $this->getLegoParams($lego_name);
    	if(!is_array($lego_params)) return false;
		if(isset($lego_params[$param_name])) return $lego_params[$param_name];
		return false;
	}
	
	public function getParam($action_name, $index, $default_value = false){
        $lego_params = $this->getLegoParams();
        if(!isset($lego_params[$action_name])) return $default_value;
		if(!isset($lego_params[$action_name][$index])) return $default_value;
		return $lego_params[$action_name][$index];
	}
    
    public function getActionParams($action = false){
    	if(!$action) $action = $this->current_action;
        $lego_params = $this->getLegoParams();
        if(!isset($lego_params[$action])) return array();
        if(!is_array($lego_params[$action])) return array();
        return $lego_params[$action];
    }
    
    public function getActionParam($index, $default_value = false){
        return $this->getParam($this->current_action, $default_value);
    }
    
    public function runner(){
        return $this->lego_runner;
    }
    
    public function root(){
    	return reset(self::$runned_legos);
	}
    
    
    public function getWebDir(){
        $dir = str_replace('\\', '/', $this->dir);
        return str_ireplace($_SERVER['DOCUMENT_ROOT'], "", $dir);
    }
    
    abstract public function getDir();
    
    public function getViewDir(){
        return static::getDir()."/view";
    }
    
    
    
    public function getJavascripts(){
    	$js = array();
    	$h = @opendir($this->dir."/js");
    	while($file = @readdir($h)){
    		if($file{0} == '.') continue;
    		if(preg_match("/(\.js|\.js\.php)$/i", $file))
    			$js[] = $this->getWebDir().'/js/'.$file;
		}
    	return $js;
	}
    

    public function getStylesheets(){
    	return $this->getView()->getStylesheets();
	}
    
    public function getHeaderBlock(){
        $csses = $this->getStylesheets();
        $jses = $this->getJavascripts();
        $ret = "";
        foreach($csses as $one) $ret .= "\n<link media='all' rel='stylesheet' href='{$one}?{$this->getVersion()}' type='text/css' media='screen' />\n";
        foreach($jses as $one) $ret .= "\n<script type='text/javascript' src='{$one}?{$this->getVersion()}'></script>\n";
        return $ret;
    } 

	
	static public function getAllJavascripts(){
		$js = array();
		foreach(self::$all_legos as $lego){
			$js = array_merge($js, $lego->getJavascripts());
		}
		return array_unique($js);
	}

	static public function getAllStylesheets(){
		$js = array();
		foreach(self::$all_legos as $lego){
			$js = array_merge($js, $lego->getStylesheets());
		}
		return array_unique($js);
	}
	
	static public function current(){
        $arr = self::$runned_legos;
        return array_pop($arr);
    }
    
    static public function _is_post(){
        return !empty($_POST);
    }
    
    static public function _get($key_name, $default_value = false){
		return self::__get_from_array($_GET, $key_name, $default_value);
	}
	
	static public function _post($key_name, $default_value = false){
		return self::__get_from_array($_POST, $key_name, $default_value);
	}
    
    static public function _sess($key_name, $default_value = false){
        return self::__get_from_array($_SESSION, $key_name, $default_value);
    }
    
    static public function _sessSet($key_name, $value){
        $_SESSION[$key_name] = $value;
    }
    
    static public function _cookie($key_name, $default_value = false){
        return self::__get_from_array($_COOKIE, $key_name, $default_value);
    }
    
    static public function _cookieSet($key_name, $value, $expire = false){
        setcookie($key_name, $value, $expire);
    }
	
	static private function __get_from_array($array, $key_name, $default_value = false){
		if(!isset($array[$key_name])) return $default_value;
		return $array[$key_name];
	}
	
	/*static public function combine($params){
		if(func_num_args() == 2)
			$params = join("=", func_get_args());
		if(is_string($params)) parse_str($params, $params);
		$get = $_GET;
		unset($get['ajax']);
		$get = array_merge($get, $params);
        foreach($get as $key => $val)
            if ($val == '?') unset($get[$key]);
        return new  UriConstructor($get);
	} */
	
	public function install(){
		if(file_exists($this->dir."/install.sql"))
			Database::query(file_get_contents($this->dir."/install.sql"));
        echo "install complete";
	}
    
    
    public function getView(){
        static $skin;
        if(!$skin) $skin = tbl_skins::skinFactory($this);
        return $skin;
    }
    
    public function hasSkins(){
        if(!is_dir($this->getViewDir())) return false;
        $h = opendir($this->getViewDir());
        $count = 0;
        while($d = readdir($h)){ 
            if(strpos($d, '.') === 0) continue;
            $count++;
        }
        return $count > 1;
    }
    
    static public function getSkins(){
        $lego_class = get_called_class();
        if(!is_dir($lego_class::getViewDir())) return array();
        $hw = opendir($lego_class::getViewDir());
        if(!$hw) return array();
        $ret = array();
        while(false !== ($fname = readdir($hw))){
            if(strpos($fname, '.') === 0) continue;
            if(!is_dir($lego_class::getViewDir().'/'.$fname)) continue;
            $title = @file_get_contents($lego_class::getViewDir().'/'.$fname.'/title.txt');
            if(!$title) $title = $fname;
            $ret[$fname] = $title;
        } 
        return $ret;
    }
    
    public function fetch($template){
        return $this->getView()->fetch($template);
    }
}

lego_abstract::staticConsturct();
